﻿#include "stdafx.h"
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#include "dib.h"



CDibRect::CDibRect(int l,int t,int r,int b)
{
	left = l; top = t; right = r; bottom = b;
}

void CDibRect::OffsetRect(int x,int y)
{
	left += x; right += x;
	top += y; bottom += y;
}

bool CDibRect::IntersectRect(CDibRect* pRect)
{
	int l = (left>pRect->left)? left : pRect->left;
	int r = (right<pRect->right)? right : pRect->right;
	int t = (top>pRect->top)? top : pRect->top;
	int b = (bottom<pRect->bottom)? bottom : pRect->bottom;
	
	if(l > r || t > b)
	{
		left = right = top = bottom = -1;
		return false;
	}
	else
	{
		left = l, right = r, top = t, bottom = b;
		return true;
	}
}

CDibRect::CDibRect(CDibRect& r)
{
	left = r.left; right = r.right; top = r.top; bottom = r.bottom;
}

int CDibRect::Width()
{
	return right-left;
}

int CDibRect::Height()
{
	return bottom-top;
}

CDibPoint CDibRect::CenterPoint()
{	
	return CDibPoint((right+left)/2,(bottom+top)/2);
}

CDibPoint CDibRect::TopLeft()
{
	return CDibPoint(left,top);
}

CDibPoint CDibRect::BottomRight()
{
	return CDibPoint(right,bottom);
}

CDibPoint::CDibPoint(int x0,int y0)
{
	x = x0; y = y0;
}

CDIB::CDIB()
{
	m_pBits = 0;
	m_pBMI = 0;

	m_bOwnBits = true;
}

CDIB::~CDIB()
{
	DestroyDIB();
}

int CDIB::Width()
{
	return m_width;
}

int CDIB::Height()
{
	return m_height;
}
void CDIB::GetRect(CDibRect* pRect)
{
	pRect->left = 0;
	pRect->right = m_width-1;
	pRect->top = 0;
	pRect->bottom = m_height-1;
}

void CDIB::CreateDIB(int width,int height,int bitcount,BYTE* pBits)
{
	CreateDIB(width,height,bitcount);
	delete m_pBits;
	m_pBits = pBits;
	
	m_bOwnBits = false;
}

void CDIB::CreateDIB(CDIB* pDib,bool bCopy)
{
	m_bOwnBits = true;
	
	CreateDIB(pDib->m_width,pDib->m_height,pDib->m_bitcount);
	if(bCopy)
	{
		memcpy(m_pBits,pDib->m_pBits,GetBitSize());
	}
}

void CDIB::CreateDIB(int width,int height,int bitcount)
{
	m_bOwnBits = true;

	DestroyDIB();
	
	m_width = width;
	m_height = height;
	m_bitcount = bitcount;
	
	if(bitcount == 24)
	{
		int www = (m_width*3 + 3 ) & ~3;
		m_pBits = new BYTE[www*m_height];
		m_pBMI = (BITMAPINFOHEADER*)new BYTE[sizeof(BITMAPINFOHEADER)];
		m_pBMI->biSize = sizeof(BITMAPINFOHEADER);
		m_pBMI->biWidth = m_width;
		m_pBMI->biHeight = m_height;
		m_pBMI->biPlanes = 1;
		m_pBMI->biBitCount = 24;
		m_pBMI->biCompression = 0;
		m_pBMI->biSizeImage = www * m_height;
		m_pBMI->biXPelsPerMeter = 1;
		m_pBMI->biYPelsPerMeter = 1;
		m_pBMI->biClrUsed = 0;
		m_pBMI->biClrImportant = 0;
	}
	else
	{
		int www = (m_width + 3 ) & ~3;
		m_pBits = new BYTE[www*m_height];
		m_pBMI = (BITMAPINFOHEADER*)new BYTE[sizeof(BITMAPINFOHEADER)+256*4];
		m_pBMI->biSize = sizeof(BITMAPINFOHEADER);

		BYTE* p = ((BYTE*)m_pBMI)+sizeof(BITMAPINFOHEADER);
		for(int i=0;i<256;i++)
		{
			p[i*4] = i;
			p[i*4+1] = i;
			p[i*4+2] = i;
			p[i*4+3] = i;
		}

		m_pBMI->biWidth = m_width;
		m_pBMI->biHeight = m_height;
		m_pBMI->biPlanes = 1;
		m_pBMI->biBitCount = 8;
		m_pBMI->biCompression = 0;
		m_pBMI->biSizeImage = www*m_height;

		m_pBMI->biXPelsPerMeter = 1;
		m_pBMI->biYPelsPerMeter = 1;
		m_pBMI->biClrUsed = 0;
		m_pBMI->biClrImportant = 0;
	}
}

void CDIB::DestroyDIB()
{
	if(m_pBits != 0 && m_bOwnBits) delete m_pBits;
	if(m_pBMI != 0) delete m_pBMI;
	m_pBits = 0;
	m_pBMI = 0;
}

void CDIB::ZeroDIB()
{
	if(m_pBits != 0)
	{
		memset(m_pBits,0,GetBitSize());
	}
}

BYTE* CDIB::GetPixelAddress(int x,int y)
{
	if(m_pBits != 0)
	{
		if(m_bitcount == 24)
			return m_pBits + (m_height-y-1) * ((m_width * 3+3)&~3) + x * 3;
		else
			return m_pBits + (m_height-y-1) * ((m_width + 3)&~3) + x;
	}		
	return 0;
}

DWORD CDIB::ReadPixel(double x,double y)
{
	int xn = (int)x;
	int yn = (int)y;
	
	if(xn < 0){ return 0;}
	if(yn < 0){ return 0;}
	if(xn > m_width-1){ return 0;}
	if(yn > m_height-1){ return 0;}

	BYTE* pBits = GetPixelAddress(xn,yn);

	x -= xn; y -= yn;
	double r00,r10,r01,r11;
	r00 = (1-x)*(1-y);
	r10 = x * (1-y);
	r01 = (1-x) * y;
	r11 = x*y;

	if(m_bitcount == 8)
	{
		double c00 = *pBits & 0xff;
		double c10 = *(pBits+1) & 0xff;
		pBits -= StorageWidth();
		double c01 = 0;
		if(r01 != 0) c01 = *pBits & 0xff;
		double c11 = 0;
		if(r11 != 0) c11 = *(pBits+1) & 0xff;
		
		return (DWORD)(c00*r00 + c01*r01 + c10*r10 + c11*r11);
	}
	else
	{
		double R00,R01,R10,R11;
		double G00,G01,G10,G11;
		double B00,B01,B10,B11;

		R00 = *(pBits+2) & 0xff;
		G00 = *(pBits+1) & 0xff;
		B00 = *pBits & 0xff;
		R10 = *(pBits+5) & 0xff;
		G10 = *(pBits+4) & 0xff;
		B10 = *(pBits+3) & 0xff;
		pBits -= StorageWidth();
		R01 = *(pBits+2) & 0xff;
		G01 = *(pBits+1) & 0xff;
		B01 = *pBits & 0xff;
		R11 = *(pBits+5) & 0xff;
		G11 = *(pBits+4) & 0xff;
		B11 = *(pBits+3) & 0xff;

		DWORD r,g,b;
		r = (BYTE)(R00*r00 + R01*r01 + R10*r10 + R11*r11);
		g = (BYTE)(G00*r00 + G01*r01 + G10*r10 + G11*r11);
		b = (BYTE)(B00*r00 + B01*r01 + B10*r10 + B11*r11);
		
		return (b<<16)+(g<<8)+r;
	}
}

void CDIB::WritePixel(int x,int y,DWORD c)
{
	if(x < 0){  return ;}
	if(y < 0){  return ;}
	if(x > m_width-1){  return ;}
	if(y > m_height-1){ return ;}

	BYTE* p = (BYTE*)GetPixelAddress(x,y);
	
	if(m_bitcount == 8)
	{
		*p = (BYTE)(c & 0xff);
	}	 
	else
	{
		*p = (BYTE)(c & 0xff);
		*(p+1) = (BYTE)((c >> 8) & 0xff);
		*(p+2) = (BYTE)((c >> 16) & 0xff);
	}
}

int CDIB::StorageWidth()
{
	if(m_pBits != 0)
	{
		if(m_bitcount == 24) 	return ((m_width * 3 + 3) & ~3);
		else 	return ((m_width + 3) & ~3);
	}
	
	return 0;
}

int CDIB::GetBitSize()
{
	return StorageWidth()*m_height;
}

bool CDIB::LoadDIB(char* filename)
{
	FILE* file = fopen(filename,"rb");
	if(file == 0) return false;
	
	DestroyDIB();

	// Load BMP file header
    BITMAPFILEHEADER FileHdr;
	fread(&FileHdr,1,sizeof(FileHdr),file);

	// BMP file must start with "BM"
    if (FileHdr.bfType != 0x4D42) 
	{
		fclose(file);
        return false;
    }

	// Load BMP InfoHeader
	BITMAPINFOHEADER bmi;
	fread(&bmi, 1,sizeof(BITMAPINFOHEADER),file);

	if(bmi.biBitCount != 24 && bmi.biBitCount != 8)
	{
		fclose(file);
		return false;
	}
	
	CreateDIB(bmi.biWidth,bmi.biHeight,bmi.biBitCount);
	memcpy(m_pBMI,&bmi,sizeof(BITMAPINFOHEADER));
	
	if(bmi.biBitCount == 8)
	{
		BYTE* p = ((BYTE*)m_pBMI)+sizeof(BITMAPINFOHEADER);
		fread(p,1,1024,file);
		for(int i=0;i<256;i++)
		{
			p[i*4] = i;
			p[i*4+1] = i;
			p[i*4+2] = i;
			p[i*4+3] = i;
		}
	}
	

	// Load BMP bits from BMP file

	fread(m_pBits,1,GetBitSize(),file);

	fclose(file);

	return true;
}

bool CDIB::SaveDIB(char* filename)
{
	FILE* file = fopen(filename,"wb");
	if(file == 0) return false;
	
	int iBISize;
	int iBitSize;
	if(m_bitcount == 8)
	{
		iBISize = sizeof(BITMAPINFOHEADER)+1024; 
		iBitSize = m_width * m_height;
	}
	else

	{
		iBISize = sizeof(BITMAPINFOHEADER);
		iBitSize = m_width * m_height * 3;
	}
	
	BITMAPFILEHEADER FileHdr;
	// BMP file must start with "BM"
    FileHdr.bfType = 0x4D42; 
    FileHdr.bfSize = sizeof(BITMAPFILEHEADER)+iBISize+iBitSize;
    FileHdr.bfReserved1 = 0;
    FileHdr.bfReserved2 = 0;
    FileHdr.bfOffBits = sizeof(BITMAPFILEHEADER) + iBISize;

	fwrite(&FileHdr,1,sizeof(FileHdr),file);
	
	fwrite(m_pBMI,1,iBISize,file);

	fwrite(m_pBits,1,GetBitSize(),file);	
	
	fclose(file);
	
	return true;
}
